
#ifndef __bubble_border_h__
#define __bubble_border_h__

#pragma once

#include "SkColor.h"
#include "view/background.h"
#include "view/border.h"

class SkBitmap;

namespace gfx
{
    class Rect;
    class Size;
}

// Renders a border, with optional arrow, and a custom dropshadow.
// This can be used to produce floating "bubble" objects with rounded corners.
class BubbleBorder : public view::Border
{
public:
    // Possible locations for the (optional) arrow.
    // 0 bit specifies left or right.
    // 1 bit specifies top or bottom.
    // 2 bit specifies horizontal or vertical.
    enum ArrowLocation
    {
        TOP_LEFT     = 0,
        TOP_RIGHT    = 1,
        BOTTOM_LEFT  = 2,
        BOTTOM_RIGHT = 3,
        LEFT_TOP     = 4,
        RIGHT_TOP    = 5,
        LEFT_BOTTOM  = 6,
        RIGHT_BOTTOM = 7,
        NONE         = 8, // No arrow. Positioned under the supplied rect.
        FLOAT        = 9  // No arrow. Centered over the supplied rect.
    };

    explicit BubbleBorder(ArrowLocation arrow_location)
        : override_arrow_offset_(0),
        arrow_location_(arrow_location),
        background_color_(SK_ColorWHITE)
    {
        InitClass();
    }

    // Returns the radius of the corner of the border.
    static int GetCornerRadius()
    {
        // We can't safely calculate a border radius by comparing the sizes of the
        // side and corner images, because either may have been extended in various
        // directions in order to do more subtle dropshadow fading or other effects.
        // So we hardcode the most accurate value.
        return 4;
    }

    // Sets the location for the arrow.
    void set_arrow_location(ArrowLocation arrow_location)
    {
        arrow_location_ = arrow_location;
    }
    ArrowLocation arrow_location() const { return arrow_location_; }

    static ArrowLocation horizontal_mirror(ArrowLocation loc)
    {
        return loc>=NONE ? loc : static_cast<ArrowLocation>(loc ^ 1);
    }

    static ArrowLocation vertical_mirror(ArrowLocation loc)
    {
        return loc>=NONE ? loc : static_cast<ArrowLocation>(loc ^ 2);
    }

    static bool has_arrow(ArrowLocation loc)
    {
        return loc>=NONE ? false : true;
    }

    static bool is_arrow_on_left(ArrowLocation loc)
    {
        return loc>=NONE ? false : !(loc & 1);
    }

    static bool is_arrow_on_top(ArrowLocation loc)
    {
        return loc>=NONE ? false : !(loc & 2);
    }

    static bool is_arrow_on_horizontal(ArrowLocation loc)
    {
        return loc>=NONE ? false : !(loc & 4);
    }

    // Sets the background color for the arrow body.  This is irrelevant if you do
    // not also set the arrow location to something other than NONE.
    void set_background_color(SkColor background_color)
    {
        background_color_ = background_color;
    }
    SkColor background_color() const { return background_color_; }

    // For borders with an arrow, gives the desired bounds (in screen coordinates)
    // given the rect to point to and the size of the contained contents.  This
    // depends on the arrow location, so if you change that, you should call this
    // again to find out the new coordinates.
    gfx::Rect GetBounds(const gfx::Rect& position_relative_to,
        const gfx::Size& contents_size) const;

    // Sets a fixed offset for the arrow from the beginning of corresponding edge.
    // The arrow will still point to the same location but the bubble will shift
    // location to make that happen. Returns actuall arrow offset, in case of
    // overflow it differ from desired.
    int SetArrowOffset(int offset, const gfx::Size& contents_size);

    // Overridden from view::Border:
    virtual void GetInsets(gfx::Insets* insets) const;

private:
    // Loads images if necessary.
    static void InitClass();

    virtual ~BubbleBorder() {}

    // Overridden from view::Border:
    virtual void Paint(const view::View& view, gfx::Canvas* canvas) const;

    void DrawEdgeWithArrow(gfx::Canvas* canvas,
        bool is_horizontal,
        SkBitmap* edge,
        SkBitmap* arrow,
        int start_x,
        int start_y,
        int before_arrow,
        int after_arrow,
        int offset) const;

    void DrawArrowInterior(gfx::Canvas* canvas,
        bool is_horizontal,
        int tip_x,
        int tip_y,
        int shift_x,
        int shift_y) const;

    // Border graphics.
    static SkBitmap* left_;
    static SkBitmap* top_left_;
    static SkBitmap* top_;
    static SkBitmap* top_right_;
    static SkBitmap* right_;
    static SkBitmap* bottom_right_;
    static SkBitmap* bottom_;
    static SkBitmap* bottom_left_;
    static SkBitmap* left_arrow_;
    static SkBitmap* top_arrow_;
    static SkBitmap* right_arrow_;
    static SkBitmap* bottom_arrow_;

    // Minimal offset of the arrow from the closet edge of bounding rect.
    static int arrow_offset_;

    // If specified, overrides the pre-calculated |arrow_offset_| of the arrow.
    int override_arrow_offset_;

    ArrowLocation arrow_location_;
    SkColor background_color_;

    DISALLOW_COPY_AND_ASSIGN(BubbleBorder);
};

// A Background that clips itself to the specified BubbleBorder and uses
// the background color of the BubbleBorder.
class BubbleBackground : public view::Background
{
public:
    explicit BubbleBackground(BubbleBorder* border) : border_(border) {}

    // Background overrides.
    virtual void Paint(gfx::Canvas* canvas, view::View* view) const;

private:
    BubbleBorder* border_;

    DISALLOW_COPY_AND_ASSIGN(BubbleBackground);
};

#endif //__bubble_border_h__